package com.file.parser.socialsecurity;

import com.file.bo.ResponseData;
import com.file.bo.socialsecurity.TianjinIndividualRecordSheet;
import com.file.bo.socialsecurity.TianjinInsuranceParticipation;
import com.file.constant.ErrorCode;
import com.file.parser.BasePdfParser;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class TianjinSocialSecurityPdfParser extends BasePdfParser {

    public ResponseData<String> parseTianjinSocialSecurityPdfParser(String daId, String filePath) {
        log.info("parseTianjinSocialSecurityPdfParser started, daId:{}", daId);
        String json = null;
        try {
            if (filePath.contains("cbzm")) {
                TianjinInsuranceParticipation tianjinInsuranceParticipation = parseTianjinInsuranceParticipation(filePath);
                json = JsonUtils.convertObjectToJson(tianjinInsuranceParticipation);
            } else if (filePath.contains("qyd")) {
                TianjinIndividualRecordSheet tianjinIndividualRecordSheet = parseTianjinIndividualRecordSheet(filePath);
                json = JsonUtils.convertObjectToJson(tianjinIndividualRecordSheet);
            } else {
                log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseTianjinSocialSecurityPdfToJson failed, new type not supported");
                return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseTianjinSocialSecurityPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseTianjinSocialSecurityPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private void parseListToBO(List<List<String>> rowList, TianjinInsuranceParticipation tianjinInsuranceParticipation) {
        String sectionName = "";
        List<TianjinInsuranceParticipation.ContributionDetails> contributionDetails = new ArrayList<>();
        tianjinInsuranceParticipation.setContributionDetails(contributionDetails);
        List<TianjinInsuranceParticipation.TianjinUrbanEmploymentInsurance> tianjinUrbanEmploymentInsurance = new ArrayList<>();
        tianjinInsuranceParticipation.setTianjinUrbanEmploymentInsurance(tianjinUrbanEmploymentInsurance);
        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(0), "险种")) {
                sectionName = "险种";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "天津市城职参保情况", "起止年月") || StringUtils.equalsAny(cellList.get(1), "缴费", "基数")) {
                sectionName = "参保情况";
                continue;
            } else if (StringUtils.equals(cellList.get(0), "备注")) {
                return;
            }
            switch (sectionName) { //NOSONAR
                case "险种":
                    TianjinInsuranceParticipation.ContributionDetails details = new TianjinInsuranceParticipation.ContributionDetails();
                    details.setInsuranceType(cellList.get(0));
                    details.setLocalContributionPeriod(cellList.get(1));
                    details.setContributionYears(cellList.get(2));
                    contributionDetails.add(details);
                    TianjinInsuranceParticipation.ContributionDetails details1 = new TianjinInsuranceParticipation.ContributionDetails();
                    details1.setInsuranceType(cellList.get(3));
                    details1.setLocalContributionPeriod(cellList.get(4));
                    details1.setContributionYears(cellList.get(5));
                    contributionDetails.add(details1);
                    break;

                case "参保情况":
                    if (cellList.get(0).matches("[0-9]{6}-[0-9]{6}")) {
                        TianjinInsuranceParticipation.TianjinUrbanEmploymentInsurance insurance = new TianjinInsuranceParticipation.TianjinUrbanEmploymentInsurance();
                        TianjinInsuranceParticipation.TianjinUrbanEmploymentInsurance.PensionInsurance pensionInsurance = new TianjinInsuranceParticipation.TianjinUrbanEmploymentInsurance.PensionInsurance();
                        insurance.setPensionInsurance(pensionInsurance);
                        TianjinInsuranceParticipation.TianjinUrbanEmploymentInsurance.UnemploymentInsurance unemploymentInsurance = new TianjinInsuranceParticipation.TianjinUrbanEmploymentInsurance.UnemploymentInsurance();
                        insurance.setUnemploymentInsurance(unemploymentInsurance);
                        insurance.setPeriod(cellList.get(0));
                        pensionInsurance.setContributionBase(cellList.get(1));
                        pensionInsurance.setPersonalContribution(cellList.get(2));
                        unemploymentInsurance.setContributionBase(cellList.get(3));
                        unemploymentInsurance.setPersonalContribution(cellList.get(4));
                        insurance.setContributionType(cellList.get(5));
                        insurance.setContributingOrganization(cellList.get(6));
                        tianjinUrbanEmploymentInsurance.add(insurance);
                    }
            }
        }
    }

    private void parseListToBO(List<List<String>> rowList, TianjinIndividualRecordSheet tianjinIndividualRecordSheet) {
        TianjinIndividualRecordSheet.UrbanEnterprisePension urbanEnterprisePension = new TianjinIndividualRecordSheet.UrbanEnterprisePension();
        TianjinIndividualRecordSheet.InstitutionalAffairsPension institutionalAffairsPension = new TianjinIndividualRecordSheet.InstitutionalAffairsPension();
        TianjinIndividualRecordSheet.EnrollmentFeeInfo enrollmentFeeInfo = new TianjinIndividualRecordSheet.EnrollmentFeeInfo();
        tianjinIndividualRecordSheet.setUrbanEnterprisePension(urbanEnterprisePension);
        tianjinIndividualRecordSheet.setInstitutionalAffairsPension(institutionalAffairsPension);
        tianjinIndividualRecordSheet.setEnrollmentFeeInfo(enrollmentFeeInfo);
        String sectionName = "";
        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(1), "城镇企业养老年限")) {
                sectionName = "城镇企业养老年限";
            } else if (StringUtils.equals(cellList.get(1), "基本养老保险") && StringUtils.equals(cellList.get(2), "基本医疗保险")) {
                sectionName = "基本养老保险";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(1), "失业保险")) {
                sectionName = "失业保险";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(1), "个人账户信息")) {
                sectionName = "个人账户信息";
                continue;
            }
            switch (sectionName) {  //NOSONAR
                case "城镇企业养老年限":
                    if (StringUtils.equals(cellList.get(2), "视同缴费年限")) {
                        urbanEnterprisePension.setDeemedContributionYears(cellList.get(3));
                        institutionalAffairsPension.setDeemedServiceYears(cellList.get(6));
                    } else if (StringUtils.equals(cellList.get(1), "核定缴费年限")) {
                        urbanEnterprisePension.setVerifiedContributionYears(cellList.get(2));
                        institutionalAffairsPension.setTransferredYearsFromOtherPlaces(cellList.get(4));
                    } else if (StringUtils.equals(cellList.get(1), "异地转入年限")) {
                        urbanEnterprisePension.setTransferredYearsFromOtherPlaces(cellList.get(2));
                        institutionalAffairsPension.setActualContributionYears(cellList.get(4));
                    } else if (StringUtils.equals(cellList.get(1), "实际缴费年限")) {
                        urbanEnterprisePension.setActualContributionYears(cellList.get(2));
                    }
                    break;
                case "基本养老保险":
                    if (StringUtils.equalsAny(cellList.get(1), "缴费月数", "单 位")) {
                        continue;
                    }
                    TianjinIndividualRecordSheet.BasicEndowmentInsurance basicEndowmentInsurance = new TianjinIndividualRecordSheet.BasicEndowmentInsurance();
                    basicEndowmentInsurance.setContributionMonths(cellList.get(1).replaceAll(" ", ""));
                    basicEndowmentInsurance.setAverageMonthlyContributionBase(cellList.get(2).replaceAll(" ", ""));
                    basicEndowmentInsurance.setFeeAmount(new TianjinIndividualRecordSheet.FeeAmount(cellList.get(3).replaceAll(" ", ""), cellList.get(4).replaceAll(" ", "")));
                    basicEndowmentInsurance.setOccupationalPensionFeeAmount(new TianjinIndividualRecordSheet.FeeAmount(cellList.get(5).replaceAll(" ", ""), cellList.get(6).replaceAll(" ", "")));
                    TianjinIndividualRecordSheet.BasicMedicalInsurance basicMedicalInsurance = new TianjinIndividualRecordSheet.BasicMedicalInsurance();
                    basicMedicalInsurance.setContributionMonths(cellList.get(7));
                    basicMedicalInsurance.setAverageMonthlyContributionBase(cellList.get(8));
                    basicMedicalInsurance.setFeeAmount(new TianjinIndividualRecordSheet.FeeAmount(cellList.get(9).replaceAll(" ", ""), cellList.get(10).replaceAll(" ", "")));
                    basicMedicalInsurance.setLargeMedicalAidPayment(cellList.get(11).replaceAll(" ", ""));
                    enrollmentFeeInfo.setBasicEndowmentInsurance(basicEndowmentInsurance);
                    enrollmentFeeInfo.setBasicMedicalInsurance(basicMedicalInsurance);

                    break;
                case "失业保险":
                    if (StringUtils.equalsAny(cellList.get(1), "缴费月数", "单 位")) {
                        continue;
                    }
                    TianjinIndividualRecordSheet.UnemploymentInsurance unemploymentInsurance = new TianjinIndividualRecordSheet.UnemploymentInsurance();
                    TianjinIndividualRecordSheet.WorkInjuryInsurance workInjuryInsurance = new TianjinIndividualRecordSheet.WorkInjuryInsurance();
                    TianjinIndividualRecordSheet.MaternityInsurance maternityInsurance = new TianjinIndividualRecordSheet.MaternityInsurance();
                    enrollmentFeeInfo.setUnemploymentInsurance(unemploymentInsurance);
                    enrollmentFeeInfo.setWorkInjuryInsurance(workInjuryInsurance);
                    enrollmentFeeInfo.setMaternityInsurance(maternityInsurance);
                    unemploymentInsurance.setContributionMonths(cellList.get(1).replaceAll(" ", ""));
                    unemploymentInsurance.setAverageMonthlyContributionBase(cellList.get(2).replaceAll(" ", ""));
                    unemploymentInsurance.setFeeAmount((new TianjinIndividualRecordSheet.FeeAmount(cellList.get(3).replaceAll(" ", ""), cellList.get(4).replaceAll(" ", ""))));
                    workInjuryInsurance.setContributionMonths(cellList.get(5).replaceAll(" ", ""));
                    workInjuryInsurance.setAverageMonthlyContributionBase(cellList.get(6).replaceAll(" ", ""));
                    workInjuryInsurance.setFeeAmount(cellList.get(7).replaceAll(" ", ""));
                    maternityInsurance.setContributionMonths(cellList.get(8).replaceAll(" ", ""));
                    maternityInsurance.setAverageMonthlyContributionBase(cellList.get(9).replaceAll(" ", ""));
                    maternityInsurance.setFeeAmount(cellList.get(10).replaceAll(" ", ""));
                    break;
                case "个人账户信息":
                    if (StringUtils.equalsAny(cellList.get(1), "基本养老保险")) {
                        TianjinIndividualRecordSheet.PersonalAccountInfo personalAccountInfo = new TianjinIndividualRecordSheet.PersonalAccountInfo();
                        tianjinIndividualRecordSheet.setPersonalAccountInfo(personalAccountInfo);
                        personalAccountInfo.setInsuranceType(cellList.get(1).replaceAll(" ", ""));
                        personalAccountInfo.setAccumulatedBalanceByLastYear(cellList.get(2).replaceAll(" ", ""));
                        personalAccountInfo.setAccountingPrincipalOfThisYear(cellList.get(3).replaceAll(" ", ""));
                        personalAccountInfo.setAccountingInterestOfThisYear(cellList.get(4).replaceAll(" ", ""));
                        personalAccountInfo.setPersonalAccountExpenditureOfThisYear(cellList.get(5).replaceAll(" ", ""));
                        personalAccountInfo.setAccumulatedBalanceByEndOfYear(cellList.get(6).replaceAll(" ", ""));
                        return;
                    }
                    break;
            }
        }
    }

    private List<List<String>> parseFileToRowList(String filePath) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        List<List<String>> rowList = new ArrayList<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());
                Rectangle rectangle = null;

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle r : rectangleList) {
                    double rectangleHeight = r.getHeight();
                    if (Double.compare(rectangleHeight, 0) > 0) {
                        rectangle = r;
                        break;
                    }
                }
                if (rectangle == null) {
                    throw new RuntimeException("rectangle is null.");
                }

                if (entry.getKey() > 1) {
                    rectangle.setTop(rectangle.getTop());
                }
                rectangle.setBottom(rectangle.getBottom() + 500);
                Page area = page.getArea(rectangle);

                // 如果每页有多个表格，解析每一个table
                List<Table> tableList = extractionAlgorithm.extract(area);
                for (Table table : tableList) {
                    for (int i = 0; i < table.getRowCount(); i++) {
                        List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                        for (int j = 0; j < table.getColCount(); j++) {
                            cellList.add(table.getCell(i, j).getText(false));
                        }
                        rowList.add(cellList);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowList;
    }

    private TianjinInsuranceParticipation parseTianjinInsuranceParticipation(String filePath) {
        TianjinInsuranceParticipation tianjinInsuranceParticipation = new TianjinInsuranceParticipation();
        String pdfText = getPdfTextByStripper(filePath).replace(System.getProperty("line.separator", "\n"), StringUtils.EMPTY);
        String date = pdfText.substring(pdfText.lastIndexOf("打印日期: ") + 5, pdfText.lastIndexOf("校验码：")).trim();
        String verificationCode = pdfText.substring(pdfText.lastIndexOf("校验码：") + 4, pdfText.lastIndexOf("姓名")).trim();
        String name = pdfText.substring(pdfText.indexOf("姓名") + 2, pdfText.indexOf("社会保障号")).trim();
        String socialSecurityNumber = pdfText.substring(pdfText.indexOf("社会保障号") + 5, pdfText.indexOf("当前参保单位名称")).trim();
        String employerName = pdfText.substring(pdfText.indexOf("当前参保单位名称") + 8, pdfText.indexOf("险种 本市")).trim();
        String remark = pdfText.substring(pdfText.lastIndexOf("备注：") + 3, pdfText.lastIndexOf(" 第")).trim().replace("\ufffd", "");
        tianjinInsuranceParticipation.setPrintDate(date);
        tianjinInsuranceParticipation.setVerificationCode(verificationCode);
        tianjinInsuranceParticipation.setName(name);
        tianjinInsuranceParticipation.setSocialSecurityNumber(socialSecurityNumber);
        tianjinInsuranceParticipation.setCurrentEmployerName(employerName);
        tianjinInsuranceParticipation.setRemarks(remark);
        List<List<String>> rowList = parseFileToRowList(filePath);
        parseListToBO(rowList, tianjinInsuranceParticipation);
        return tianjinInsuranceParticipation;
    }

    private TianjinIndividualRecordSheet parseTianjinIndividualRecordSheet(String filePath) {
        TianjinIndividualRecordSheet tianjinIndividualRecordSheet = new TianjinIndividualRecordSheet();
        TianjinIndividualRecordSheet.PersonalInfo personalInfo = new TianjinIndividualRecordSheet.PersonalInfo();
        tianjinIndividualRecordSheet.setPersonalInfo(personalInfo);
        String pdfText = getPdfTextByStripper(filePath).replace(System.getProperty("line.separator", "\n"), StringUtils.EMPTY);

        String name = pdfText.substring(pdfText.indexOf("姓  名") + 4, pdfText.indexOf("社会保障号码")).trim();
        String socialSecurityNumber = pdfText.substring(pdfText.indexOf("社会保障号码") + 6, pdfText.indexOf("性 别")).trim();
        String gender = pdfText.substring(pdfText.indexOf("性 别") + 3, pdfText.indexOf("年 龄")).trim();
        String age = pdfText.substring(pdfText.indexOf("年 龄") + 3, pdfText.indexOf("单位名称")).trim();
        String employerName = pdfText.substring(pdfText.indexOf("单位名称") + 4, pdfText.indexOf("单位类型")).trim();
        String employerType = pdfText.substring(pdfText.indexOf("单位类型") + 4, pdfText.indexOf("参加工作时间")).trim();
        String startOfWork = pdfText.substring(pdfText.indexOf("参加工作时间") + 6, pdfText.indexOf("联系地址")).trim();
        String contactAddress = pdfText.substring(pdfText.indexOf("联系地址") + 4, pdfText.indexOf("邮政编码")).trim();
        String postalCode = pdfText.substring(pdfText.indexOf("邮政编码") + 4, pdfText.indexOf("手机号码")).trim();
        String phoneNumber = pdfText.substring(pdfText.indexOf("手机号码") + 4, pdfText.indexOf("城镇企业养老")).trim();
        String note = pdfText.substring(pdfText.lastIndexOf("注：") + 2, pdfText.lastIndexOf("数据统计截")).trim();
        String dataStatisticsUntil = pdfText.substring(pdfText.lastIndexOf("数据统计截至：") + 7, pdfText.lastIndexOf("固化数据打印时间")).trim();
        String printTime = pdfText.substring(pdfText.lastIndexOf("打印时间：") + 5).trim();
        personalInfo.setName(name);
        personalInfo.setSocialSecurityNumber(socialSecurityNumber);
        personalInfo.setGender(gender);
        personalInfo.setAge(age);
        personalInfo.setEmployerName(employerName);
        personalInfo.setEmployerType(employerType);
        personalInfo.setStartOfWork(startOfWork);
        personalInfo.setContactAddress(contactAddress);
        personalInfo.setPostalCode(postalCode);
        personalInfo.setPhoneNumber(phoneNumber);
        tianjinIndividualRecordSheet.setNote(note);
        tianjinIndividualRecordSheet.setDataStatisticsUntil(dataStatisticsUntil);
        tianjinIndividualRecordSheet.setPrintTime(printTime);
        List<List<String>> rowList = parseFileToRowList(filePath);
        parseListToBO(rowList, tianjinIndividualRecordSheet);
        return tianjinIndividualRecordSheet;
    }

    public static void main(String[] args) {
        TianjinSocialSecurityPdfParser tianjinSocialSecurityPdfParser = new TianjinSocialSecurityPdfParser();
        String json, filePath;
        // 参保证明
        filePath = "D:\\data\\file\\socialsecurity\\天津\\app-gjzwfw-dzsb_cbzm.pdf";
        json = tianjinSocialSecurityPdfParser.parseTianjinSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);

        // 权益单
        filePath = "D:\\data\\file\\socialsecurity\\天津\\app-gjzwfw-dzsb_qyd.pdf";
        json = tianjinSocialSecurityPdfParser.parseTianjinSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);

    }

}
